package com.baiduspring.web.user;

import com.baiduspring.dao.entity.SmsCode;
import com.baiduspring.dao.entity.User;
import com.baiduspring.error.BaiduSpringException;
import com.baiduspring.function.elasticsearch.operation.Doc;
import com.baiduspring.function.elasticsearch.operation.QueryInput;
import com.baiduspring.service.sms.SmsCodeService;
import com.baiduspring.service.specialcolumn.SpecialColumnIndexEnum;
import com.baiduspring.service.user.FollowAuthorService;
import com.baiduspring.service.user.UserService;
import com.baiduspring.utils.ResponseResult;
import com.baiduspring.utils.SystemCode;
import com.baiduspring.utils.bean.PageBean;
import com.baiduspring.utils.elasticsearch.ElasticSearchUtils;
import com.baiduspring.utils.servlet.WebUtils;
import com.baiduspring.vo.ResultsVO;
import com.baiduspring.vo.UserVO;
import com.baiduspring.vo.ValidateVO;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;

@RestController
@Scope("prototype")
@RequestMapping("/user")
@Slf4j
public class UserController {
    @Resource
    private UserService userService;
    @Resource
    private FollowAuthorService followAuthorService;
    @Resource
    private SmsCodeService smsCodeService;

    /**
     * 用户注册
     *
     * @param vo 参数
     * @return 返回注册结果
     */
    @PostMapping("/register")
    public ResponseResult register(UserVO vo, HttpServletRequest request) {
        ResponseResult result = new ResponseResult();
        try {
            String ip = WebUtils.getTerminalRealIP(request);
            vo.setIp(ip);
            userService.register(vo);
            result.setCode(SystemCode.SUCCESS);
            result.setMessage("恭喜您，注册成功");
        } catch (BaiduSpringException e) {
            result.setCode(SystemCode.FAIL);
            result.setMessage(e.getMessage());
            log.error("注册错误，原因：", e);
        } catch (Exception e) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("抱歉，注册失败");
            log.error("注册错误，原因：", e);
        }
        return result;
    }

    /**
     * 用户登录
     *
     * @param name     用户名
     * @param password 密码
     * @return 返回登录信息
     */
    @PostMapping("/login")
    public ResponseResult login(String name, String password, HttpSession session) {
        ResponseResult result = new ResponseResult();
        try {
            Optional<User> userOptional = userService.login(name, password);

            userOptional.ifPresent(user -> {
                session.setAttribute("user", user);

                session.setAttribute("name", !StringUtils.isEmpty(user.getNickname()) ? user.getNickname() :
                        !StringUtils.isEmpty(user.getUserName()) ? user.getUserName() : !StringUtils.isEmpty(user.getPhoneNumber()) ? user.getPhoneNumber() : "");
            });

            result.setCode(SystemCode.SUCCESS);
            result.setMessage("登录成功，即将跳转...");
        } catch (BaiduSpringException e) {
            result.setCode(SystemCode.FAIL);
            result.setMessage(e.getMessage());
            log.error("登录错误，原因：", e);
        } catch (Exception e) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("登录失败，请确认登录信息并再次登录");
            log.error("登录错误，原因：", e);
        }
        return result;
    }

    @GetMapping("/{account}")
    public ModelAndView indexView(HttpServletRequest request, @PathVariable("account") Long account) {
        ModelAndView view = new ModelAndView("user/index");
        LoginStatus.status(request, view);

        userService.modifyHomepageViewsByAccount(account);

        Optional<User> optional = userService.getByAccount(account);
        optional.ifPresent(user -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            view.addObject("user", userVO);
        });

        QueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchPhraseQuery("authorAccount", account));

        String[] indies = {SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_INDEX.getValue()};
        String[] types = {SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_TYPE.getValue()};

        Map<String, Class> outputFields = Maps.newHashMap();
        outputFields.put("id", String.class);
        outputFields.put("title", String.class);
        outputFields.put("orig", Integer.class);
        outputFields.put("label", String.class);
        outputFields.put("contentTxt", String.class);
        outputFields.put("authorAccount", Long.class);
        outputFields.put("uriMark", Long.class);
        outputFields.put("readNum", Integer.class);
        outputFields.put("collectNum", Integer.class);
        outputFields.put("likesNum", Integer.class);
        outputFields.put("updateDate", Long.class);

        Doc<String, SortOrder> sortFields = new Doc<>();
        sortFields.put("updateDate", SortOrder.DESC);

        QueryInput input = new QueryInput();
        input.setIndices(indies);
        input.setTypes(types);
        input.setOutputFields(outputFields);
        input.setSortFields(sortFields);

        ElasticSearchUtils.multipleFieldValueQuery(input, queryBuilder, ResultsVO.class, output -> {
            view.addObject("blogs", output.getResults());
            view.addObject("contribution", output.getTotal());
        });

        int countMyFollew = followAuthorService.countMyFollew(account);
        int countMyFans = followAuthorService.countMyFans(account);

        view.addObject("countMyFollew", countMyFollew);
        view.addObject("countMyFans", countMyFans);

        return view;
    }

    @GetMapping("/{account}/curr")
    public List<ResultsVO> blogsList(@PathVariable("account") Long account, PageBean pageBean) {

        QueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchPhraseQuery("authorAccount", account));

        String[] indies = {SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_INDEX.getValue()};
        String[] types = {SpecialColumnIndexEnum.SPECIAL_COLUMN_BLOG_TYPE.getValue()};

        Map<String, Class> outputFields = Maps.newHashMap();
        outputFields.put("id", String.class);
        outputFields.put("title", String.class);
        outputFields.put("orig", Integer.class);
        outputFields.put("label", String.class);
        outputFields.put("contentTxt", String.class);
        outputFields.put("authorAccount", Long.class);
        outputFields.put("uriMark", Long.class);
        outputFields.put("readNum", Integer.class);
        outputFields.put("collectNum", Integer.class);
        outputFields.put("likesNum", Integer.class);
        outputFields.put("updateDate", Long.class);

        Doc<String, SortOrder> sortFields = new Doc<>();
        sortFields.put("updateDate", SortOrder.DESC);

        QueryInput input = new QueryInput();
        input.setIndices(indies);
        input.setTypes(types);
        input.setOutputFields(outputFields);
        input.setSortFields(sortFields);

        input.setCurrentPage(pageBean.currentPage());
        input.setPageSize(PageBean.PAGESIZE);

        ArrayList<ResultsVO> list = Lists.newArrayList();
        ElasticSearchUtils.multipleFieldValueQuery(input, queryBuilder, ResultsVO.class, output -> {
            for (Object o : output.getResults()) {
                ResultsVO vo = (ResultsVO) o;
                vo.setSummary(vo.summary());
                list.add(vo);
            }
        });

        return list;
    }

    /**
     * 退出登录状态,重定向到首页界面
     *
     * @param session  参数
     * @param response 参数
     */
    @GetMapping("/logout")
    public void logout(HttpSession session, HttpServletResponse response) {
        session.removeAttribute("user");
        try {
            response.sendRedirect("/");
        } catch (IOException e) {
            log.error("退出，重定向错误，原因：", e);
        }
    }

    /**
     * 获取登录状态
     *
     * @param session 参数
     * @return 布尔值 true：登录  false：未登录
     */
    @GetMapping("/login_status")
    public boolean loginStatus(HttpSession session) {
        Object o = session.getAttribute("user");
        return !Objects.isNull(o);
    }

    /**
     * 登录/注册页面
     *
     * @param session 参数
     * @return 视图
     */
    @GetMapping("/join")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ModelAndView loginAndRegister(HttpSession session) {
        ModelAndView modelAndView = new ModelAndView("user/login-register");

        String login = UUID.randomUUID().toString();
        String register = UUID.randomUUID().toString();
        session.setAttribute("loginSessrionId", login);
        session.setAttribute("registerSessrionId", register);

        return modelAndView;
    }

    /**
     * 弹层登录页
     *
     * @param session 参数
     * @return 视图
     */
    @GetMapping("/alert/loginview")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ModelAndView alertLoginView(HttpSession session) {
        return new ModelAndView("user/login");
    }

    /**
     * 弹层注册页
     *
     * @param session 参数
     * @return 视图
     */
    @GetMapping("/alert/registerview")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ModelAndView alertRegisterView(HttpSession session) {
        return new ModelAndView("user/register");
    }

    @GetMapping("/retrieve/password")
    public ModelAndView retrievePassword() {
        return new ModelAndView("user/retrieve-password");
    }

    @GetMapping("/valid/fogot/{mobile}/{smscode}/{validCode}")
    public ResponseResult<String> validFogot(HttpSession session, @PathVariable("mobile") String mobile,
                                             @PathVariable("smscode") String smscode, @PathVariable("validCode") String validCode) {
        ResponseResult<String> result = new ResponseResult<>();
        result.setCode(SystemCode.SUCCESS);

        if (StringUtils.isEmpty(validCode)) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("图形验证码不能为空");
            return result;
        }
        if (StringUtils.isEmpty(mobile)) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("手机号码不能为空");
            return result;
        }
        if (StringUtils.isEmpty(smscode)) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("短信验证码不能为空");
            return result;
        }

        String sessionCode = session.getAttribute("_code").toString();
        if (!validCode.equalsIgnoreCase(sessionCode)) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("图形验证码说如错误");
            return result;
        }

        Optional<SmsCode> smsCode = smsCodeService.getByMobile(Long.valueOf(mobile), smscode);
        if (!smsCode.isPresent()) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("短信验证码错误");
            return result;
        }

        String uuid = UUID.randomUUID().toString();
        session.setAttribute(uuid, uuid);
        session.setMaxInactiveInterval(60);

        result.setData(uuid);
        return result;
    }

    @GetMapping("/retrieve/set/newpwd/{sessionId}/{mobile}")
    public ModelAndView retrieveSetNewPassword(HttpSession session, @PathVariable String sessionId, @PathVariable("mobile") Long mobile) {
        ModelAndView view = new ModelAndView("user/retrieve-set-new-password");

        Object attrSessionId = session.getAttribute(sessionId);
        if (Objects.isNull(attrSessionId)) {
            throw new BaiduSpringException("页面不存在");
        }

        view.addObject("sessionId", sessionId);
        view.addObject("mobile", mobile);
        return view;
    }

    @PostMapping("/update_password")
    public ResponseResult updatePassword(String mobile, String password) {
        Preconditions.checkArgument(Objects.nonNull(mobile), "手机号码不能为空");
        Preconditions.checkArgument(!StringUtils.isEmpty(password), "密码不能为空");

        ResponseResult<Object> result = new ResponseResult<>();
        result.setCode(SystemCode.SUCCESS);

        try {
            userService.modifyPasswordByMobile(mobile, password);
        } catch (BaiduSpringException e) {
            result.setCode(SystemCode.FAIL);
            result.setMessage("密码修改失败");
        }
        return result;
    }

    @GetMapping("/uniqueness")
    public ValidateVO<String> uniqueness(String name) {
        if (StringUtils.isEmpty(name)) {
            return new ValidateVO<>(false, "手机号码不能为空");
        }

        Optional<User> userOptional = userService.uniqueness(name);
        if (userOptional.isPresent()) {
            return new ValidateVO<>(false, "手机号码已经存在");
        }

        return new ValidateVO<>(true);
    }

    @GetMapping("/isempty")
    public ValidateVO<String> isEmpty(String name) {
        if (StringUtils.isEmpty(name)) {
            return new ValidateVO<>(false, "手机号码不能为空");
        }

        Optional<User> userOptional = userService.uniqueness(name);
        if (!userOptional.isPresent()) {
            return new ValidateVO<>(false, "手机号码不存在");
        }

        return new ValidateVO<>(true);
    }

}
